# script to test how the mailer deals with failures
use strict;
use warnings;

use Arcos::Test;

BEGIN {

    # setup short timeouts to keep the test time needed under control
    Arcos::Test->make_config_changes(SMTPWriterTimeout        => 4,
                                     SMTPWriterMaxRetry       => 5,
                                     MailerPauseCheckInterval => 1);
}

use Test::More;
use File::Spec::Functions qw/catfile catdir/;
use File::Temp qw(tempdir);

use Arcos::Test::Script;
use Arcos::TestData;
use Arcos::DB::MailingMessage;
use Arcos::Conf qw(ArcosRoot MailerMaxProcesses);
use Arcos::DB::MailingSent;
use Arcos::DB::MailingBounce;
use Arcos::DB::MailingFailed;
use Arcos::DB::LastRun;
use Arcos::DB::Segment;
use Arcos::JobQueue;

Arcos::Test->plan_if_queued_stopped('no_plan');

our $MAX_SECONDS = 20;

$ENV{ARCOS_TEST_SMTP_PORT}    = 2525;
$ENV{ARCOS_TEST_SMTP_ADDRESS} = 'localhost';

# startup test SMTP server, writing files to a tmp dir
my $dir = tempdir(DIR => catdir(ArcosRoot, 'tmp'));
my $cmd =
    catfile(ArcosRoot, 'bin', 'arcos_test_smtp_server_ctl')
  . ' restart '
  . " --port $ENV{ARCOS_TEST_SMTP_PORT} --dir $dir";
system($cmd)
  and die "Unable to start test SMTP server.\n";

# restart queue from this process, so it gets our %ENV
$cmd = catfile(ArcosRoot, 'bin', 'arcos_queue_ctl') . ' start';
system($cmd);

my $creator = Arcos::TestData->new();

# setup enough slow senders to keep the mailer busy for at least 20 seconds
my $total = MailerMaxProcesses * 20;    # need to put this much in the queue
my $count = $total / 2;
my @people;
for (1 .. $count) {
    push @people,
      $creator->create_contact_info(email => "sleep-2\@slow${_}.com")->person;
}

# send the data to the warehouse
$creator->load_warehouse();

foreach my $test_mode (qw/stop restart/) {

    # create a message for tests - this will have a small body but the
    # pause feature doesn't get bothered by that anymore
    my ($segment) = Arcos::DB::Segment->search({name => "All Members"});
    my $message = $creator->create_mailing_message(segment => $segment);

    # send a message to the people
    my $job_id =
      Arcos::JobQueue->submit_job(
                                type       => 'mailing',
                                parameters => {
                                    message_id => $message->id,
                                    test_send  => 0,
                                    templates  => {
                                        html_header => '<h1>HTML Header</h1>',
                                        html_footer => '<h1>HTML Footer</h1>',
                                        text_header => 'Text Header',
                                        text_footer => 'Text Footer',
                                    },
                                });

    # wait for it to start
    {
        my $timer = 0;
        while ($timer < $MAX_SECONDS
               and not Arcos::DB::MailingSent->count_search(
                                                  message_id => $message->id))
        {
            sleep 1;
            $timer++;
        }
        if ($timer == $MAX_SECONDS) {
            fail("mailing job did not start in $MAX_SECONDS seconds");
        } else {
            pass('mailing job started');
        }
    }

    $cmd = catfile(ArcosRoot, 'bin', 'arcos_queue_ctl') . " $test_mode";
    system($cmd);

    if ($test_mode eq 'stop') {

        # they shouldn't all have completed
        my $sent =
          Arcos::DB::MailingSent->count_search(message_id => $message->id);
        ok($sent < @people);

        # each sent should have a matching directory entry
        opendir(DIR, $dir) or die $!;
        my @files = grep { -f "$dir/$_" } readdir(DIR);
        closedir(DIR) or die $!;
        is(@files, $sent, "bulkmail(send count), directory: $dir");

        # restart the mailing
        $cmd = catfile(ArcosRoot, 'bin', 'arcos_queue_ctl') . ' start';
        system($cmd);
    }

    {
        my $timer = 0;
        while ($timer < $MAX_SECONDS) {
            my $updated_message =
              Arcos::DB::MailingMessage->retrieve($message->id);
            if ($updated_message->mailing_status eq 'Sent') { last }
            sleep 1;
            $timer++;
        }
        if ($timer == $MAX_SECONDS) {
            fail("mailing job did not complete in $MAX_SECONDS seconds");
        } else {
            pass('mailing job is complete');
        }
    }

    # now they should all be sent
    my $all_sent =
      Arcos::DB::MailingSent->count_search(message_id => $message->id);
    is($all_sent, @people);

    # and each should be in the directory
    opendir(DIR, $dir) or die $!;
    my @all_files = grep { -f "$dir/$_" } readdir(DIR);
    closedir(DIR) or die $!;
    is(@all_files, @people, "bulkmail(send count), directory: $dir");

    # delete MailingSent entries so that we can delete the message.
    my @sent_records =
      Arcos::DB::MailingSent->search(message_id => $message->id);
    my @failed_records =
      Arcos::DB::MailingFailed->search(message_id => $message->id);
    $_->delete for (@sent_records, @failed_records);

    # clean out mail collected by test smtp server
    system("rm -rf $dir/\*");
}

$cmd = catfile(ArcosRoot, 'bin', 'arcos_test_smtp_server_ctl') . ' stop ';
system($cmd);

$cmd = catfile(ArcosRoot, 'bin', 'arcos_queue_ctl') . ' stop';
system($cmd);

$creator->cleanup();
$creator->cleanup_jobs();

Arcos::Test->restore_original_config(1);
